﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace MetroLightKit.ConvertSvg
{
    public partial class Main : Form
    {
        private Working _dossier;
        private int _nbErrors = 0;
        readonly BackgroundWorker _bgWorker = new BackgroundWorker();
        private const string SourceCombo = @".\_source.txt";
        private const string DestinationCombo = @".\_destination.txt";
        private const string SiteCombo = @".\_site.txt";
        private readonly FileSystemWatcher _fsWatch = new FileSystemWatcher(@".\", "_*.txt");

        public Main()
        {
            InitializeComponent();
            _dossier = new Working();
            _dossier.ReturnMessageWorker += new EventHandler<MessageWorkerArgs>(DossierReturnMessageWorker);
            _bgWorker.WorkerReportsProgress = true;
            _bgWorker.WorkerSupportsCancellation = true;

            _bgWorker.DoWork += new DoWorkEventHandler(BgWorker_DoWork);
            _bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BgWorker_RunWorkerCompleted);
            _bgWorker.ProgressChanged += new ProgressChangedEventHandler(BgWorker_ProgressChanged);
            btCancel.Enabled = false;
            LoadProperties();
        }

        private void LoadProperties()
        {
            tbPrefix.Text = Properties.Settings.Default.Prefix;
            
            LoadCombo(SourceCombo, cbSources, Properties.Settings.Default.Source);
            LoadCombo(DestinationCombo, cbDestination, Properties.Settings.Default.Destination);
            LoadSiteCombo(Properties.Settings.Default.Site);

            cbSites_TextChanged(null, null);
            cbDestination_TextChanged(null, null);
            cbSources_TextChanged(null, null);
        }

        #region FileWatcher

        private void InitWatchFs()
        {
            _fsWatch.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            _fsWatch.SynchronizingObject = this;
            _fsWatch.Changed += new FileSystemEventHandler(_fsWatch_Changed);
            _fsWatch.EnableRaisingEvents = true;
        }

        private void ResetWatchFs()
        {
            if (_fsWatch.EnableRaisingEvents)
            {
                _fsWatch.SynchronizingObject = null;
                _fsWatch.Changed -= new FileSystemEventHandler(_fsWatch_Changed);
                _fsWatch.EnableRaisingEvents = false;
            }
        }

        void _fsWatch_Changed(object sender, FileSystemEventArgs e)
        {
            ResetWatchFs();
            try
            {
                switch (e.Name)
                {
                    case "_source.txt":
                        LoadCombo(SourceCombo, cbSources, cbSources.Text);
                        break;
                    case "_destination.txt":
                        LoadCombo(DestinationCombo, cbDestination, cbDestination.Text);
                        break;
                    case "_site.txt":
                        LoadSiteCombo(cbSites.Text);
                        break;
                }
            }
            catch (Exception)
            {
            }
        }
        #endregion

        #region Combo
        private void LoadCombo(string pathTxt, ComboBox box, string selectedText)
        {
            box.Items.Clear();
            if (File.Exists(pathTxt))
            {
                try
                {
                    using (var stRead = new StreamReader(pathTxt))
                    {
                        while (!stRead.EndOfStream)
                        {
                            var res = stRead.ReadLine();
                            if (!String.IsNullOrWhiteSpace(res))
                                box.Items.Add(res);
                        }
                    }
                }
                catch (Exception)
                {

                }
            }
            if (!String.IsNullOrWhiteSpace(selectedText))
            {
                foreach (var item in box.Items)
                {
                    if (item.Equals(selectedText))
                        box.SelectedItem = item;
                }
                if (box.SelectedItem == null)
                {
                    box.Items.Add(selectedText);
                    box.SelectedItem = selectedText;
                }
            }
        }
        private void LoadSiteCombo(string selectedText)
        {
            cbSites.Items.Clear();
            if (File.Exists(SiteCombo))
            {
                try
                {
                    using (var stRead = new StreamReader(SiteCombo))
                    {
                        while (!stRead.EndOfStream)
                        {
                            var res = stRead.ReadLine();
                            if (!String.IsNullOrWhiteSpace(res))
                                cbSites.Items.Add(new WebSite(res));
                        }
                    }
                }
                catch (Exception)
                {

                }
            }
            if (!String.IsNullOrWhiteSpace(selectedText))
            {
                foreach (var item in cbSites.Items)
                {
                    if (item.Equals(selectedText))
                        cbSites.SelectedItem = item;
                }
            }
        }
        protected void ChangeSaveCombo(string pathTxt, ComboBox box, string selectedText)
        {
            if (box.Items.Contains(selectedText))
                box.SelectedItem = selectedText;
            else
            {
                box.Items.Add(selectedText);
                box.SelectedItem = selectedText;
                try
                {
                    using (var stWrite = new StreamWriter(pathTxt, false))
                    {
                        foreach (var item in box.Items)
                        {
                            stWrite.WriteLine(item);
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }
        #endregion

        #region OpenUri

        private void Execute(string path)
        {
            if (path.StartsWith("http:"))
                System.Diagnostics.Process.Start(path);
            else
            {
                var fi = new FileInfo(path);
                if (fi.Exists)
                {
                    System.Diagnostics.Process.Start(string.Format("file://{0}", fi.FullName));
                    return;
                }
                else
                {
                    var di = new DirectoryInfo(path);
                    if (di.Exists)
                    {
                        System.Diagnostics.Process.Start(string.Format("file://{0}", di.FullName));
                        return;
                    }
                }
            }
            MessageBox.Show(String.Format("Impossible d'ouvrir : {0}", path));
        }
        #endregion

        #region Worker
        
        void BgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            
            _nbErrors = 0;
            if (e.Argument is Working.Phase)
            {
                switch ((Working.Phase)e.Argument)
                {
                    case Working.Phase.Download:
                        _dossier.DownloadSvgNodes();
                        break;
                    case Working.Phase.Convert:
                        _dossier.ConvertSvgToXamlResource();
                        break;
                }
            }
        }

        void DossierReturnMessageWorker(object sender, MessageWorkerArgs e)
        {
            _bgWorker.ReportProgress(e.Percent.GetValueOrDefault(0), e);
        }

        void BgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (_bgWorker.CancellationPending)
                _dossier.CancelPending = true;

            var message = e.UserState as MessageWorkerArgs;

            if (message != null)
            {
                //var log = FabriqueLog();

                switch (message.Type)
                {
                    case TypeMessage.Start:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Bold);
                        rtbSortieTraitements.SelectionColor = Color.Black;
                        lbTraitements.Text = @"Working ...";
                        break;
                    case TypeMessage.Information:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Regular);
                        rtbSortieTraitements.SelectionColor = Color.Black;
                        break;
                    case TypeMessage.Error:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Regular);
                        rtbSortieTraitements.SelectionColor = Color.Red;
                        _nbErrors++;
                        lbTraitements.Text = String.Format("Working ... {0} {1}", _nbErrors, _nbErrors > 1 ? "errors" : "error");
                        break;
                    case TypeMessage.EndError:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Bold);
                        rtbSortieTraitements.SelectionColor = Color.Red;
                        _nbErrors++;
                        lbTraitements.Text = String.Format("End with {0} {1}", _nbErrors, _nbErrors > 1 ? "errors" : "error");
                        break;
                    case TypeMessage.End:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Bold);
                        rtbSortieTraitements.SelectionColor = Color.Black;
                        lbTraitements.Text = @"End";
                        if (_nbErrors > 0)
                            lbTraitements.Text += String.Format(" avec {0} {1}", _nbErrors, _nbErrors > 1 ? "errors" : "error");
                        break;
                    case TypeMessage.Cancel:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Regular);
                        rtbSortieTraitements.SelectionColor = Color.Orange;
                        lbTraitements.Text = @"Cancel";
                        if (_nbErrors > 0)
                            lbTraitements.Text += String.Format(" with {0} {1}", _nbErrors, _nbErrors > 1 ? "errors" : "error");
                        break;
                    default:
                        rtbSortieTraitements.SelectionFont = new Font(rtbSortieTraitements.SelectionFont, FontStyle.Regular);
                        rtbSortieTraitements.SelectionColor = Color.Black;
                        break;
                }
                if (_nbErrors > 0)
                    lbTraitements.ForeColor = Color.Red;
                else
                    lbTraitements.ForeColor = Color.Black;

                pbartraitements.Value = message.Percent.GetValueOrDefault(0);
                rtbSortieTraitements.AppendText(message.Message);
                rtbSortieTraitements.AppendText(System.Environment.NewLine);
                rtbSortieTraitements.ScrollToCaret();
            }

        }
        
        void BgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btPhase1.Enabled = true;
            btPhase2.Enabled = true;
            btCancel.Enabled = false;
        }

        #endregion


        private void btPhase1_Click(object sender, EventArgs e)
        {
            InitWorking();
            _bgWorker.RunWorkerAsync(Working.Phase.Download);
        }

        private void btPhase2_Click(object sender, EventArgs e)
        {
            InitWorking();
            _bgWorker.RunWorkerAsync(Working.Phase.Convert);
        }

        public void InitWorking()
        {
            cbSites_SelectedIndexChanged(null, null);
            btPhase1.Enabled = false;
            btPhase2.Enabled = false;
            btCancel.Enabled = true;
            ResetWatchFs();
        }

        private void btSource_Click(object sender, EventArgs e)
        {
            var folder = new FolderBrowserDialog { Description = @" Choix du répertoire source" };

            if (!string.IsNullOrWhiteSpace(cbSources.Text))
                folder.SelectedPath = cbSources.Text;
            if (folder.ShowDialog() == DialogResult.OK)
            {
                ChangeSaveCombo(SourceCombo, cbSources, folder.SelectedPath);
            }
        }

        private void btDestination_Click(object sender, EventArgs e)
        {
            var open = new OpenFileDialog();
            open.Filter = "Resources (*.xaml)|*.xaml";
            open.CheckFileExists = false;
          
            if (!string.IsNullOrWhiteSpace(cbSources.Text))
                open.InitialDirectory = cbDestination.Text;
            if (open.ShowDialog() == DialogResult.OK)
            {
                ChangeSaveCombo(DestinationCombo, cbDestination, open.FileName);
            }
        }

        private void cbSources_TextChanged(object sender, EventArgs e)
        {
            _dossier.SvgDirectoryPath = cbSources.Text;
            Properties.Settings.Default.Source = cbSources.Text;
        }

        private void cbDestination_TextChanged(object sender, EventArgs e)
        {
            _dossier.XamlResourceFileOut = cbDestination.Text;
            Properties.Settings.Default.Destination = cbDestination.Text;
        }

        private void cbSites_TextChanged(object sender, EventArgs e)
        {

        }

        private void tbPrefix_TextChanged(object sender, EventArgs e)
        {
            _dossier.PrefixNameInXaml = tbPrefix.Text;
            Properties.Settings.Default.Prefix = tbPrefix.Text;
        }

        private void lbSvgDirectory_Click(object sender, EventArgs e)
        {
            InitWatchFs();
            Execute(SourceCombo);
        }

        private void lbSvgSite_Click(object sender, EventArgs e)
        {
            InitWatchFs();
            Execute(SiteCombo);
        }

        private void lbDestination_Click(object sender, EventArgs e)
        {
            InitWatchFs();
            Execute(DestinationCombo);
        }

        private void btOpenDestination_Click(object sender, EventArgs e)
        {
            Execute(cbDestination.Text);
        }

        private void btOpenSource_Click(object sender, EventArgs e)
        {
            Execute(cbSources.Text);
        }

        private void btCancel_Click(object sender, EventArgs e)
        {
            _dossier.CancelPending = true;
        }

        private void cbSites_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbSites.SelectedItem != null)
            {
                var webSite = cbSites.SelectedItem as WebSite;

                if (webSite != null)
                {
                    tbXpathName.Text = webSite.XpathName;
                    tbXpathSvg.Text = webSite.XpathSvgs;
                    _dossier.Site = webSite;
                    Properties.Settings.Default.Site = webSite.Url;
                }
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Execute("http://metrolightkit.codeplex.com/");
        }

    }
}
